import _ from 'lodash'
import moment from 'moment'
import {article, section} from './lablog.js'

article("try/catch并不‘纯’，当一个错误抛出的时候，我们并没有收到返回值，反而是得到了一个警告。有了 Either 就能更好地处理错误")

const Left = function(x) {this.__value = x}
Left.of = function(x) {return new Left(x)}
Left.prototype.map = function(f) {return this}

const Right = function(x) {this.__value = x}
Right.of = function(x) {return new Right(x)}
Right.prototype.map = function(f) {return Right.of(f(this.__value))}

const getAge = _.curry((now, user) => {
    const birthday = moment(user.birthday, 'YYYY-MM-DD')
    if (!birthday.isValid()) return Left.of("Birth date could not be parsed!")
    return Right.of(now.diff(birthday, 'years'))
})
console.log(getAge(moment(), {birthday: '1996-03-26'}))
console.log(getAge(moment(), {birthday: 'ballons.'}))


const map = _.curry((f, any_functor) => {
    return any_functor.map(f)
})
const add = _.curry((i1, i2) => i1 + i2)
const concat = _.curry((s1, s2) => s1 + s2)
const fortune = _.flowRight(concat("If you survive, you will be "), add(1))
const zoltar = _.flowRight(map(console.log), map(fortune), getAge(moment()))
console.log(zoltar({birthday: '1998-10-14'}))
console.log(zoltar({birthday: 'balloons!'}))
section("一个函数在调用的过程中，如果被 map 包裹了，那么它就从一个非 functor 函数转换为一个 functor 函数。我们将这个过程叫做 lift。")
section("一般情况下，普通函数更适合操作普通的数据类型而不是容器类型，在必要的时候通过lift变为合适的容器去操作容器类型。这样的好处是能够得到更简单、重用性更高的函数。它们能够随需求而变，兼容任意 functor")
section("Either 并不仅仅只对合法性检查这种一般性的错误作用非凡，对于一些更严重的、能够中断程序运行的错误如文件丢失等，同样效果显著。")
section("Either 能做的事情远不止如此，还表示逻辑或，体现了范畴学中的 coproduct 概念等等。作为一个 functor 我们用它来处理错误")

const either = _.curry((f, g, e) => {
    switch(e.constructor) {
        case Left: return f(e.__value);
        case Right: return g(e.__value);
    }
})

const id = function(x) {return x}
const zoltar2 = _.flowRight(console.log, either(id, fortune), getAge(moment()))
zoltar2({birthday: '2006-8-26'})
zoltar2({birthday: 'boom!'})


